using System;
using System.Collections;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.Admin
{
    /// <summary>
    /// AdminUserProfile is a web page that renders a single user's detailed
    /// information.  The logged in user can edit the profiles' contact details.
    /// In addition the logged in user can register or unregister the user that 
    /// is detailed on the page. 
    /// </summary>
    public partial class AdminUserProfile : BasePage
    {
        #region Constants

        private const string ApplicationBitmask = "ApplicationBitmask";
        private const string ApplicationUserTableName = "ApplicationUser";
        private const string EmailTableName = "Email";
        private const string FwkDomainUserId = "FwkDomainUserId";
        private const string InsightApplicationBitmask = "4";
        private const string IsActiveBitmask = "IsActiveBitmask";
        private const string ModuleBitmask = "ModuleBitmask";
        private const string ModuleRoleBitmask = "ModuleRoleBitmask";

        private const string OrganizationTableName = "Organization";
        private const string PageModeKey = "PageMode_19C81B4F-9314-4b64-A951-FFE91C4360D0";
        private const string PageOrgModeKey = "PageOrgModeKey_19C81B4F-9314-4b64-A951-FFE91C4360D0";
        private const string PrimaryTypeId = "1";
        private const string SecondaryTypeId = "2";
        private const string TelephoneTableName = "Telephone";
        private const string userKey = "user_8BCBCA67-E92E-494d-8160-EA17CD0CD784";

        #endregion

        #region Instance variables (Private)

        private ICachePolicy cachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private Properties

        /// <summary>
        /// Gets the relevant user object from the cache if there is one otherwise loads 
        /// a new one based on the cached personID and caches it.
        /// </summary>
        private new User User
        {
            get
            {
                User user = cachePolicy.GetCachedObject(User.CacheKey) as User;

                Hashtable h = (Hashtable) pageCachePolicy.GetCachedObject(Keys.IncomingDataKey);
                int personId = (int) h[Keys.PersonIdKey];

                if (user == null || (user.PersonId != personId))
                {
                    user = new User(cachePolicy);
                    user.Load(DataAccess.GetConnectionString(), personId);
                    user.Cache();
                }

                return user;
            }
        }

        /// <summary>
        /// Used to set and get whether or not the page is currently in edit mode.
        /// </summary>
        private bool IsPageInEditMode
        {
            get
            {
                object o = ViewState[PageModeKey];
                return (o == null) ? false : (bool) o;
            }
            set { ViewState[PageModeKey] = value; }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the page is loaded.  The state of the controls is initialized
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            breadCrumb.Add("User Profile", "AdminUserProfile.aspx", Settings.GetKeyValue("BreadCrumb.Admin.AdminUserProfilePageLevel", 2));

            if (!IsPostBack && postbackGuard.IsValid)
            {
                try
                {
                    InitializeControls();
                }
                catch (Exception ex)
                {
                    annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
                    ExceptionReport.WriteToEventLog("AdminUserProfile", ex, true, ExceptionReport.ReportType.Error);
                }
            }
        }

        /// <summary>
        /// Occurs when registration button is clicked to initiate the register / 
        /// de-registration process.  The user's application user object is updated
        /// and saved, then the old user object is uncached.  If the user is getting
        /// registered we redirect to the User Module Access page.  If the user is 
        /// getting removed (unregistered) we stay reinitialize the controls and stay
        /// on this page.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnRegister(object sender, ImageClickEventArgs e)
        {
            bool registerUser = (register.ImageUrl == "../Images/b_register_user.gif") ? true : false;
            UpdateApplicationUser(registerUser);
            User.ApplicationUserDetail.Save(DataAccess.GetConnectionString());
            User.UnCache();

            if (registerUser)
            {
                //redirect to the first step of registration - add user modules page
                Response.Redirect(Settings.GetKeyValue("SubNavigation.Admin.UserDetails.UserModuleAccessURL", ""));
            }
            else
            {
                //stay on this page
                InitializeControls();
            }
        }

        /// <summary>
        /// Occurs when the Edit/Save Profile Details button is clicked.  If 
        /// the page is in edit mode, the details are saved and editable controls 
        /// subsequently disabled.  If the page is not in edit mode, the editable
        /// controls are enabled and the cancel button is made visible.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnEditSave(object sender, ImageClickEventArgs e)
        {
            annunciator.Message = "";
            try
            {
                if (IsPageInEditMode)
                {
                    if (primaryEmail.Text != User.Details.PrimaryEmail ||
                        secondaryEmail.Text != User.Details.SecondaryEmail)
                    {
                        User.Details.DoNotUpdateEmail = true;
                    }

                    if (primaryPhoneAreaCode.Text != User.Details.PrimaryPhoneAreaCode ||
                        primaryPhoneNumberPrefix.Text != User.Details.PrimaryPhoneNumberPrefix ||
                        primaryPhoneNumberSuffix.Text != User.Details.PrimaryPhoneNumberSuffix)
                    {
                        User.Details.DoNotUpdatePhone = true;
                    }

                    UpdateOrganizationInfo();
                    UpdateEmailAddress(PrimaryTypeId);
                    UpdateEmailAddress(SecondaryTypeId);
                    UpdateTelephoneNumber(PrimaryTypeId);
                    UpdateTelephoneNumber(SecondaryTypeId);

                    User.Save(DataAccess.GetConnectionString());
                    User.UnCache();
                    SetEditControlsProperties(false, "DataInput");
                }
                else
                {
                    SetEditControlsProperties(true, "UserInput");
                }
            }
            catch (Exception ex)
            {
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Occus when the cancel button is clicked.  The editable controls
        /// are disabled.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnCancel(object sender, ImageClickEventArgs e)
        {
            InitializeControls();
        }

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            adminUserManagementSubNavigation.Reset();
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Initializes the components/members used by this page.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnInit(EventArgs e)
        {
            InitializeComponent();
            base.OnInit(e);
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Sets initial state on the page's controls.
        /// </summary>
        private void InitializeControls()
        {
            lastName.Text = User.LastName;
            firstName.Text = User.FirstName;
            userName.Text = User.Username;
            organizationSelectors.SelectedOrganizationID = User.OrganizationId;
            primaryEmail.Text = User.Details.PrimaryEmail;
            secondaryEmail.Text = User.Details.SecondaryEmail;
            primaryPhoneAreaCode.Text = User.Details.PrimaryPhoneAreaCode;
            primaryPhoneNumberPrefix.Text = User.Details.PrimaryPhoneNumberPrefix;
            primaryPhoneNumberSuffix.Text = User.Details.PrimaryPhoneNumberSuffix;
            secondaryPhoneAreaCode.Text = User.Details.SecondaryPhoneAreaCode;
            secondaryPhoneNumberPrefix.Text = User.Details.SecondaryPhoneNumberPrefix;
            secondaryPhoneNumberSuffix.Text = User.Details.SecondaryPhoneNumberSuffix;
            registered.Text = User.IsRegistered ? "Yes" : "No";
            domainStatus.Text = User.DomainStatus;

            SetEditControlsProperties(false, "DataInput");
            register.ImageUrl = (User.IsRegistered) ? "../Images/b_remove_user.gif" : "../Images/b_register_user.gif";
        }

        /// <summary>
        /// Used to set the state of the page's editable controls except the organization editor.
        /// </summary>
        /// <param name="isEnabled">Used to enable or disable editable controls and to set the text on 
        /// the EditSaveProfileInfo button.</param>
        /// <param name="cssClass">Used to set the style on the editable controls.</param>
        private void SetEditControlsProperties(bool isEnabled, string cssClass)
        {
            editSaveProfileInfo.ImageUrl = isEnabled ? "../Images/b_save.gif" : "../Images/b_edit.gif";
            cancel.Visible = isEnabled;
            register.Visible = !isEnabled;
            IsPageInEditMode = isEnabled;

            organizationSelectors.IsGrayOutMode = !isEnabled;
            organizationSelectors.CssClass = cssClass;

            primaryEmail.Enabled = isEnabled;
            primaryPhoneAreaCode.Enabled = isEnabled;
            primaryPhoneNumberPrefix.Enabled = isEnabled;
            primaryPhoneNumberSuffix.Enabled = isEnabled;
            secondaryEmail.Enabled = isEnabled;
            secondaryPhoneAreaCode.Enabled = isEnabled;
            secondaryPhoneNumberPrefix.Enabled = isEnabled;
            secondaryPhoneNumberSuffix.Enabled = isEnabled;

            primaryEmail.CssClass = cssClass;
            primaryPhoneAreaCode.CssClass = cssClass;
            primaryPhoneNumberPrefix.CssClass = cssClass;
            primaryPhoneNumberSuffix.CssClass = cssClass;
            secondaryEmail.CssClass = cssClass;
            secondaryPhoneAreaCode.CssClass = cssClass;
            secondaryPhoneNumberPrefix.CssClass = cssClass;
            secondaryPhoneNumberSuffix.CssClass = cssClass;
        }

        /// <summary>
        /// Saves the application user data based on data contained in the cached User object's Data Container.
        /// </summary>
        /// <param name="registerUser">Indicates whether we are performing a registration or un-registration operation.</param>
        private void UpdateApplicationUser(bool registerUser)
        {
            DataTable applicationUserTable = User.ApplicationUserDetail.GetDataContainer().Tables[ApplicationUserTableName];

            if (applicationUserTable.Rows.Count > 0)
            {
                //update
                DataRow row = applicationUserTable.Rows[0];
                int applicationBitmask = !registerUser ? ((int) row[ApplicationBitmask] - Convert.ToInt32(InsightApplicationBitmask)) : ((int) row[ApplicationBitmask] + Convert.ToInt32(InsightApplicationBitmask));
                row[ApplicationBitmask] = applicationBitmask;
                row[IsActiveBitmask] = applicationBitmask;
            }
            else if (registerUser)
            {
                //insert
                DataRow row = applicationUserTable.NewRow();

                row[ApplicationBitmask] = InsightApplicationBitmask;
                row[IsActiveBitmask] = InsightApplicationBitmask;
                row[FwkDomainUserId] = User.DomainUserId;
                row[ModuleBitmask] = 0;
                row[ModuleRoleBitmask] = 0;

                applicationUserTable.Rows.Add(row);
            }
        }

        /// <summary>
        /// Sets the email data contained in the cached User object's DataSet using values
        /// from the page's controls.
        /// </summary>
        /// <param name="emailTypeId">The type of email address to be updated (1 for primary, 2 for secondary)</param>
        private void UpdateEmailAddress(string emailTypeId)
        {
            TextBox emailTextBox = (emailTypeId == PrimaryTypeId) ? primaryEmail : secondaryEmail;

            DataTable emailTable = User.GetDataContainer().Tables[EmailTableName];
            DataRow[] emailRows = emailTable.Select(String.Format("TypeId = {0}", emailTypeId));

            System.Diagnostics.Trace.Assert(emailRows.Length == 1 || emailRows.Length == 0);

            DataRow emailRow;
            string emailAddress = emailTextBox.Text.Trim();

            if (emailRows.Length == 1)
            {
                emailRow = emailRows[0];
                if (emailAddress == String.Empty)
                {
                    //delete
                    emailRow["EmailAddress"] = DBNull.Value;
                }
                else
                {
                    //update
                    emailRow = emailRows[0];
                    if ((string) emailRow["EmailAddress"] != emailAddress)
                    {
                        emailRow["EmailAddress"] = emailAddress;
                    }
                }
            }
            else
            {
                if (emailAddress != String.Empty)
                {
                    //insert
                    emailRow = emailTable.NewRow();
                    emailRow["EmailAddress"] = emailAddress;
                    emailRow["PersonId"] = User.PersonId;
                    emailRow["TypeId"] = emailTypeId;

                    emailTable.Rows.Add(emailRow);
                }
            }
        }

        /// <summary>
        /// Sets the telephone data contained in the cached User object's DataSet using values
        /// from the page's controls.
        /// </summary>
        /// <param name="telephoneNumberTypeId">The type of telephone number to be updated (1 for primary, 2 for secondary)</param>
        private void UpdateTelephoneNumber(string telephoneNumberTypeId)
        {
            TextBox numberPrefixTextBox,
                numberSuffixTextBox,
                areaCodeTextBox;

            if (telephoneNumberTypeId == PrimaryTypeId)
            {
                numberPrefixTextBox = primaryPhoneNumberPrefix;
                numberSuffixTextBox = primaryPhoneNumberSuffix;
                areaCodeTextBox = primaryPhoneAreaCode;
            }
            else
            {
                numberPrefixTextBox = secondaryPhoneNumberPrefix;
                numberSuffixTextBox = secondaryPhoneNumberSuffix;
                areaCodeTextBox = secondaryPhoneAreaCode;
            }

            DataTable telephoneNumberTable = User.GetDataContainer().Tables[TelephoneTableName];
            DataRow[] telephoneNumberRows = telephoneNumberTable.Select(String.Format("TypeId = {0}", telephoneNumberTypeId));

            System.Diagnostics.Trace.Assert(telephoneNumberRows.Length == 1 || telephoneNumberRows.Length == 0);

            DataRow telephoneNumberRow;
            string numberPrefix = numberPrefixTextBox.Text.Trim();
            string numberSuffix = numberSuffixTextBox.Text.Trim();
            string areaCode = areaCodeTextBox.Text.Trim();

            if (telephoneNumberRows.Length == 1)
            {
                telephoneNumberRow = telephoneNumberRows[0];

                if (numberPrefix == String.Empty &&
                    numberSuffix == String.Empty &&
                        areaCode == String.Empty)
                {
                    //delete
                    telephoneNumberRow["AreaCode"] = DBNull.Value;
                    telephoneNumberRow["Number"] = DBNull.Value;
                }
                else
                {
                    if (numberPrefix != String.Empty &&
                        numberSuffix != String.Empty &&
                            areaCode != String.Empty)
                    {
                        //update
                        telephoneNumberRow = telephoneNumberRows[0];
                        if ((string) telephoneNumberRow["AreaCode"] != areaCode)
                        {
                            telephoneNumberRow["AreaCode"] = areaCode;
                        }

                        string phoneNumber = String.Format("{0}-{1}",
                            numberPrefix,
                            numberSuffix);

                        if ((string) telephoneNumberRow["Number"] != phoneNumber)
                        {
                            telephoneNumberRow["Number"] = phoneNumber;
                        }
                    }
                    else
                    {
                        throw new Exception("Unable to update telephone number.  The Area Code and Number must be complete.");
                    }
                }
            }
            else
            {
                if (numberPrefix != String.Empty &&
                    numberSuffix != String.Empty &&
                        areaCode != String.Empty)
                {
                    //insert
                    telephoneNumberRow = telephoneNumberTable.NewRow();
                    telephoneNumberRow["AreaCode"] = areaCode;

                    string phoneNumber = String.Format("{0}-{1}",
                        numberPrefix,
                        numberSuffix);
                    telephoneNumberRow["Number"] = phoneNumber;

                    telephoneNumberRow["PersonId"] = User.PersonId;
                    telephoneNumberRow["TypeId"] = telephoneNumberTypeId;

                    telephoneNumberTable.Rows.Add(telephoneNumberRow);
                }
                else if (numberPrefix != String.Empty ||
                    numberSuffix != String.Empty ||
                        areaCode != String.Empty)
                {
                    throw new Exception("Unable to add telephone number.  The Area Code and Number must be complete.");
                }
            }
        }

        /// <summary>
        /// Sets the organization data contained in the cached User object's DataSet using values
        /// from the page's controls.
        /// </summary>
        private void UpdateOrganizationInfo()
        {
            User.Details.OrganizationId = organizationSelectors.SelectedOrganizationID;
        }

        #endregion
    }
}